#ifndef __MAKE_ENUM_WITH_STR__
#define __MAKE_ENUM_WITH_STR__

#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>

// #define MAKE_ENUM(name, ...)                              \
//     enum name { __VA_ARGS__, name##__COUNT };             \
//     template <typename NameOrInt>                         \
//     inline std::string name##ToStr(NameOrInt value) {     \
//         std::string              enumName = #name;        \
//         std::string              str      = #__VA_ARGS__; \
//         int                      len      = str.length(); \
//         std::vector<std::string> strings;                 \
//         std::ostringstream       temp;                    \
//         for (int i = 0; i < len; i++) {                   \
//             if (isspace(str[i]))                          \
//                 continue;                                 \
//             else if (str[i] == ',') {                     \
//                 strings.emplace_back(temp.str());         \
//                 temp.str(std::string());                  \
//             }                                             \
//             else                                          \
//                 temp << str[i];                           \
//         }                                                 \
//         strings.emplace_back(temp.str());                 \
//         return strings[static_cast<int>(value)];          \
//     }

// #define MAKE_ENUM_CLASS(name, ...)                        \
//     enum class name { __VA_ARGS__, name##__COUNT };       \
//     inline std::string name##ToStr(name value) {          \
//         std::string              enumName = #name;        \
//         std::string              str      = #__VA_ARGS__; \
//         int                      len      = str.length(); \
//         std::vector<std::string> strings;                 \
//         std::ostringstream       temp;                    \
//         for (int i = 0; i < len; i++) {                   \
//             if (isspace(str[i]))                          \
//                 continue;                                 \
//             else if (str[i] == ',') {                     \
//                 strings.emplace_back(temp.str());         \
//                 temp.str(std::string());                  \
//             }                                             \
//             else                                          \
//                 temp << str[i];                           \
//         }                                                 \
//         strings.emplace_back(temp.str());                 \
//         return strings[static_cast<int>(value)];          \
//     }


#include "repeat.h"

#define ENUM_DECL_STATEMENT(key, value) key = value,
#define ENUM_MAP_EMPLACE_1(_, key) {key, #key},
#define ENUM_MAP_EMPLACE_1class(name, key) {name::key, #key},
#define ENUM_MAP_EMPLACE_2(_, key, __) {key, #key},
#define ENUM_MAP_EMPLACE_2class(name, key, _) {name::key, #key},


#define MAKE_ENUM(name, if_class, ...)                                                                                             \
    enum if_class      name { __VA_ARGS__ };                                                                                       \
    inline std::string name##ToStr(name value) {                                                                                   \
        static std::unordered_map<name, std::string> name##_map{FOR_EACH_ARG(ENUM_MAP_EMPLACE_1##if_class, 1, name, __VA_ARGS__)}; \
        return name##_map.at(value);                                                                                               \
    }


#define MAKE_ENUM_I(name, if_class, ...)                                                                                           \
    enum if_class      name { FOR_EACH(ENUM_DECL_STATEMENT, 2, __VA_ARGS__) };                                                     \
    inline std::string name##ToStr(name value) {                                                                                   \
        static std::unordered_map<name, std::string> name##_map{FOR_EACH_ARG(ENUM_MAP_EMPLACE_2##if_class, 2, name, __VA_ARGS__)}; \
        return name##_map.at(value);                                                                                               \
    }

// MAKE_ENUM(Name1, class, A, B)
// MAKE_ENUM(Name2, , C, D)

// MAKE_ENUM_I(Name3, class, E, 1, F, 2)
// MAKE_ENUM_I(Name4, , G, 1, H, 2)

// 声明枚举时同时声明其枚举值转为字符串的函数，支持 enum, enum class, enum with int


#endif // __MAKE_ENUM_WITH_STR__